home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / ccheck.zip / CCHECK.C < prev    next >
C/C++ Source or Header  |  1985-06-23  |  21KB  |  758 lines

  1. /*
  2.  * CCHECK.C -- Aztec C Version of CCHK, 06/23/85
  3.  *
  4.  *
  5.  * Copyright: The Regents of the University of California
  6.  *   [Note - since Steve Draper distributed cchk.c over
  7.  *    Usenet, I assume it's effectively in the public
  8.  *    domain. JCM]
  9.  *
  10.  * Title:  ccheck
  11.  *
  12.  * Purpose: To find and report all badly matched openers and
  13.  *   closers plus assignment/equality confusions
  14.  *   in a c source file.
  15.  *
  16.  * Author:  Steve Draper, expanding cnest by Tom Anderson
  17.  *
  18.  * Usage:  ccheck [-q] [-v] <filename1> <filename2> ...
  19.  *
  20.  * History (in reverse order to minimize reading time for updates):
  21.  *
  22.  *   June 18, 1985  Converted to Aztec C - removed BDS C code  -  Rick Moore
  23.  *
  24.  *   January 9, 1983  Single BDS/UNIX source created
  25.  *      as CCHECK.C  -- Jeff Martin
  26.  *
  27.  *   December 29, 1982 Adapted for BDS C --
  28.  *       Jeff Martin at home.
  29.  *
  30.  *   December 20, 1982 Converted to cchk --
  31.  *       Steve Draper at UCSD
  32.  *
  33.  *   December 9, 1982 Jeffrey Mogul at Stanford
  34.  *    - checks for unclosed comment at end of file.
  35.  *
  36.  *   December 3, 1982 creation date --
  37.  *      Tom Anderson at microsof!fluke
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include <ctype.h>
  42.  
  43. #define TRUE 1
  44. #define FALSE 0
  45. #define SPACE 32
  46.  
  47. #define BRACE 1
  48. #define SQBRAK  2
  49. #define PAREN 3
  50. #define IF 4
  51. #define IFCOND 5
  52. #define WHLCOND 6
  53. #define THEN 7
  54. #define ELSE 8
  55.  
  56. #define STACKSIZ 64
  57.  
  58. struct brak {
  59.     int type, b_indent, b_ln;
  60. } stack[STACKSIZ];
  61.  
  62. #define rmbrak(N) (top -= N, stackc -= N)
  63. #define myungetc(C)  ungetc(((C) == '\n' ? SPACE : (C)), infile)
  64.  
  65. #define VFLAG "-v"
  66. #define QFLAG "-q"
  67. #define SFLAG "-s"
  68.  
  69. int firsttime; /* This was a static in mygetchar() */
  70.  
  71. int mygetchar(), pr();
  72. void checkelse(), newbrak(), checkcloser(), prtype();
  73.  
  74. FILE *infile;
  75. int ln, indent, commindent, stackc, commln;
  76. int singlequoterr, oddsinglequote, bracecnt, parencnt, sqbrakcnt;
  77. int errstatus, wstatus;
  78. int errnmb, wnmb;
  79. int verbose;
  80. char *filename;
  81. struct brak *top;
  82.  
  83. main(argc, argv)
  84. unsigned argc ;
  85. char *argv[] ;
  86. {
  87.     register int c ;
  88.     int i;
  89.     int doubleqflag;
  90.     unsigned file_index;
  91.  
  92.     wnmb = 0;
  93.     verbose = 0;
  94.     file_index = 1;
  95.  
  96.     while (argc > 1  &&  argv[file_index][0] == '-') {
  97.         if (strcmp(argv[file_index], VFLAG) == 0)
  98.             verbose++;
  99.         if (strcmp(argv[file_index], QFLAG) == 0)
  100.             wnmb = -2;
  101.         if (strcmp(argv[file_index], SFLAG) == 0)
  102.             wnmb = -2;
  103.         file_index++;
  104.         argc--;
  105.     }
  106.  
  107.     do {
  108.         /* INIT for each file */
  109.         firsttime = 1;
  110.         doubleqflag = 0;
  111.         errstatus = wstatus = 0;
  112.         ln = 1;
  113.         indent = 0;
  114.         commindent = 0;
  115.         singlequoterr = oddsinglequote = parencnt = sqbrakcnt = bracecnt =
  116.           0;
  117.         errnmb = 0;
  118.         if (wnmb > -2)
  119.             wnmb = 0;
  120.         newbrak(0);
  121.  
  122.         if (argc == 1) {
  123.             infile = stdin;
  124.             filename = NULL;
  125.         } else {
  126.             if ((infile = fopen(argv[file_index], "r")) == (FILE * ) NULL) {
  127.                 fprintf (stdout, "%s: Can't access %s\n", argv[0], argv[file_ind
  128.                 continue;
  129.             }
  130.             filename = argv[file_index];
  131.         }
  132.  
  133.         while ( ( c = mygetchar()) !=  EOF ) {
  134.             if (verbose == 2) {
  135.                 for (i = stackc; i > 0; i--) {
  136.                     printf("%c %d: type ", c, i);
  137.                     prtype(stack[i].type);
  138.                     printf(", indent %d, line %d.\n", stack[i].b_indent, stack[i
  139.                 }
  140.             }
  141.  
  142.             switch (c) {
  143.             case ';':
  144.                 ungetc(SPACE, infile);
  145.                 while (top->type == ELSE)
  146.                     rmbrak(1);
  147.                 if (top->type == THEN) {
  148.                     rmbrak(1);
  149.                     checkelse();
  150.                 }
  151.                 break;
  152.  
  153.             case '!':
  154.             case '>':
  155.             case '<':
  156.                 /* swallow legit. '=' chars */
  157.                 c = mygetchar();
  158.                 if (c != '=')
  159.                     myungetc(c);
  160.                 break;
  161.  
  162.             case '=':
  163.                 if ((top - 1)->type == IFCOND  ||  (top - 1)->type == WHLCOND) {
  164.                     c = mygetchar();
  165.                     if (c != '=') {
  166.                         myungetc(c);
  167.                         if (pr(1))
  168.                             printf("Assignment instead of equals in conditional,
  169.                                ln);
  170.                     }
  171.                 }
  172.                 break;
  173.  
  174.             case '\n':
  175.             case SPACE:
  176.                 c = mygetchar();
  177.                 switch (c) {
  178.                 case 'i':
  179.                     /* if */
  180.                     c = mygetchar();
  181.                     if (c == 'f'
  182.                       && !isalpha(c = fgetc(infile)) && !isdigit(c)) {
  183.                         ungetc(c, infile);
  184.                         newbrak(IF);
  185.                         while ((c = mygetchar()) == SPACE ||  c == '\n')
  186.                             ;
  187.                         if (c != '(') {
  188.                             if (pr(1))
  189.                                 printf("Bad if (no condition) line %d.\n",
  190.                                    ln);
  191.                             rmbrak(1);
  192.                         } else
  193.                             newbrak(IFCOND);
  194.                         myungetc(c);
  195.                     } else
  196.                         myungetc(c);
  197.                     break;
  198.                 case 'w':
  199.                     /* while */
  200.                     if ((c = mygetchar()) == 'h'
  201.                       &&  (c = mygetchar()) == 'i'
  202.                       &&  (c = mygetchar()) == 'l'
  203.                       &&  (c = mygetchar()) == 'e'
  204.                       &&  !isalpha(c = fgetc(infile))  &&  !isdigit(c)) {
  205.                         ungetc(c, infile);
  206.                         while ((c = mygetchar()) == SPACE ||  c == '\n')
  207.                             ;
  208.                         if (c != '(') {
  209.                             if (pr(1))
  210.                                 printf("Bad while (no condition) line %d.\n",
  211.                                    ln);
  212.                         } else
  213.                             newbrak(WHLCOND);
  214.                         myungetc(c);
  215.                     } else
  216.                         myungetc(c);
  217.                     break;
  218.                 case 'e':
  219.                     /* else */
  220.                     myungetc(c);
  221.                     checkelse();
  222.                     break;
  223.  
  224.                 default:
  225.                     myungetc(c);
  226.                     break;
  227.                 }
  228.                 break;
  229.  
  230.             case '*':
  231.                 /* close comment ? */
  232.                 c = mygetchar();
  233.                 if (c != '/') {
  234.                     myungetc(c);
  235.                     break;
  236.                 }
  237.  
  238.                 if (pr(1))
  239.                     printf
  240.                       ("Line %d: Comment close without open, indent %d\n",
  241.                       ln, indent);
  242.  
  243.                 break;
  244.  
  245.             case '\'':
  246.                 if ((c = fgetc(infile)) != '\\') {
  247.                     if (c == '\''  ||  (c = fgetc(infile)) != '\'') {
  248.                         if (pr(1))
  249.                             printf("Bad character constant line %d\n", ln);
  250.                         singlequoterr = 1;
  251.                     }
  252.                 } else if (!isdigit(c = fgetc(infile))) {
  253.                     if ((c = fgetc(infile)) != '\'') {
  254.                         if (pr(1))
  255.                             printf("Bad character constant with \\ line %d\n",
  256.                                ln);
  257.                     }
  258.                 } else {
  259.                     if (isdigit(c = fgetc(infile)))
  260.                         if (isdigit(c = fgetc(infile)))
  261.                             c = fgetc(infile);
  262.                     if (c != '\'')
  263.                         if (pr(1))
  264.                             printf("Bad character constant with \\0 line %d\n",
  265.                                ln);
  266.                 }
  267.  
  268.                 if (c != '\'') {
  269.                     ungetc(c, infile);
  270.                     oddsinglequote = !oddsinglequote;
  271.                     singlequoterr = 1;
  272.                 }
  273.                 break;
  274.  
  275.             case '"':
  276.                 do {
  277.                     c = fgetc(infile);
  278.                     if (c == EOF) {
  279.                         if (pr(2))
  280.                             printf("Error: '\"' quoted string not ended by end o
  281.                         break;
  282.                     } else if (c == '\n') {
  283.                         if (doubleqflag == 0)
  284.                             if (pr(0))
  285.                                 printf("Warning: '\"' quoted string not ended by
  286.                                    ln);
  287.                         doubleqflag = 1;
  288.                         ln++;
  289.                     } else if (c == '\\') {
  290.                         c = SPACE;
  291.                         fgetc(infile);
  292.                     }
  293.                 } while (c != '"');
  294.                 doubleqflag = 0;
  295.                 break;
  296.  
  297.             case '{':
  298.                 if (stackc  &&  indent < top->b_indent)
  299.                     if (pr(0))
  300.                         printf("Indent jumps backwards line %d.\n", ln);
  301.                 newbrak(BRACE);
  302.                 break;
  303.  
  304.             case '}':
  305.                 checkcloser(BRACE);
  306.                 while (top->type == ELSE)
  307.                     rmbrak(1);
  308.                 if (top->type == THEN) {
  309.                     rmbrak(1);
  310.                     checkelse();
  311.                 }
  312.                 break;
  313.  
  314.             case '(':
  315.                 if (stackc  &&  indent < top->b_indent)
  316.                     if (pr(0))
  317.                         printf("Indent jumps backwards line %d.\n", ln);
  318.                 newbrak(PAREN);
  319.                 break;
  320.  
  321.             case ')':
  322.                 checkcloser(PAREN);
  323.                 if (top->type == IFCOND) {
  324.                     rmbrak(1);
  325.                     newbrak(THEN);
  326.                 } else if (top->type == WHLCOND)
  327.                     rmbrak(1);
  328.                 break;
  329.  
  330.             case '[':
  331.                 if (stackc  &&   indent < top->b_indent)
  332.                     if (pr(0))
  333.                         printf("Indent jumps backwards line %d.\n", ln);
  334.                 newbrak(SQBRAK);
  335.                 break;
  336.  
  337.             case ']':
  338.                 checkcloser(SQBRAK);
  339.                 break;
  340.  
  341.             default:
  342.                 break;
  343.  
  344.             }
  345.         }
  346.  
  347.         fclose(infile);
  348.  
  349.         while (stackc > 0) {
  350.             pr(2);
  351.             fputs("Unclosed brak at EOF: ", stdout);
  352.             prtype(top->type);
  353.             printf(" opened on line %d.\n", top->b_ln);
  354.             switch (top->type) {
  355.             case BRACE:
  356.                 bracecnt++;
  357.                 break;
  358.             case SQBRAK:
  359.                 sqbrakcnt++;
  360.                 break;
  361.             case PAREN:
  362.                 parencnt++;
  363.                 break;
  364.             default:
  365.                 break;
  366.             }
  367.             rmbrak(1);
  368.         }
  369.  
  370.         if ((i = (oddsinglequote || bracecnt || sqbrakcnt || parencnt)) ||
  371.           errstatus) {
  372.             pr(2);
  373.             printf("Summary:\n");
  374.         } else {
  375.             if (filename != NULL) {
  376.                 fputs(filename, stdout);
  377.                 fputs(": ", stdout);
  378.             }
  379.             printf(" OK\n");
  380.         }
  381.         if (oddsinglequote)
  382.             printf("\tOdd number of single quotes.\n");
  383.         if (bracecnt)
  384.             printf("\t%d too few %s braces.\n", abs(bracecnt), (bracecnt >
  385.               0 ? "closing" : "opening"));
  386.         if (sqbrakcnt)
  387.             printf("\t%d too few %s square brackets.\n", abs(sqbrakcnt), (sqbrak
  388.               > 0 ? "closing" : "opening"));
  389.         if (parencnt)
  390.             printf("\t%d too few %s parentheses.\n", abs(parencnt), (parencnt
  391.               > 0 ? "closing" : "opening"));
  392.         if (errstatus && !i)
  393.             printf("\tPossible error(s), but no net delimiter imbalance.\n");
  394.         putchar('\n');
  395.     } while (++file_index < argc);
  396.  
  397.     exit(errstatus ? 2 : wstatus);
  398. }
  399.  
  400. int mygetchar()
  401. {
  402.     register int c;
  403.  
  404.     c = fgetc(infile);
  405.  
  406.     /*
  407.     if (c == ';') {
  408.  ungetc(SPACE, infile);
  409.  return(';');
  410.     }
  411.     */
  412.     if (c == '/') {    /* open comment ? */
  413.         c = fgetc(infile);
  414.         if (c != '*') {
  415.             ungetc(c, infile);
  416.             return('/');
  417.         }
  418.         commln = ln;
  419.         commindent = indent;
  420.  
  421.         while (1) {
  422.             c = fgetc(infile);
  423.  
  424.             if (c == EOF) {   /* last comment never ended */
  425.                 if (pr(2))
  426.                     printf
  427.                       ("Comment opened line %d unclosed by end of file.\n",
  428.                       commln);
  429.                 break; /* Get out of this loop! */
  430.             } else if (c == '/') {  /* nested comment ? */
  431.                 if ((c = fgetc(infile)) == '*') {
  432.                     if (pr(0))
  433.                         fprintf(stdout,
  434.                           "Nested comment: line %d, indent %d.  First open: line
  435.                              ln, indent, commln, commindent);
  436.                 } else
  437.                     ungetc(c, infile);
  438.             } else if (c == '*') {  /* end comment ? */
  439.                 if ((c = fgetc(infile)) == '/') {
  440.                     if (indent != commindent  &&  indent - 1 != commindent)
  441.                         if (pr(0))
  442.                             printf(
  443.                               "Indent of comment close doesn't match open: lines
  444.                                      commln, ln, commindent, indent);
  445.  
  446.                     break;    /* only exit from loop, except EOF */
  447.                 } else
  448.                     ungetc(c, infile);
  449.             } else if (c == '\n') {
  450.                 do {
  451.                     if (c == SPACE)
  452.                         indent++;
  453.                     else if (c == '\t')
  454.                         indent = ((indent + 8) / 8) * 8;
  455.                     else if (c == '\n') {
  456.                         ln++;
  457.                         indent = 0;
  458.                     }
  459.                 } while (isspace(c = fgetc(infile)));
  460.                 ungetc(c, infile);
  461.             }
  462.         }
  463.         return(SPACE);
  464.  
  465.     }
  466.  
  467.     if (c == '\n'  ||  firsttime == 1) {
  468.         firsttime = 0;
  469. lf:
  470.         while (1) {
  471.             if (c == SPACE)
  472.                 indent++;
  473.             else if (c == '\t')
  474.                 indent = ((indent + 8) / 8) * 8;
  475.             else if (c == '\n') {
  476.                 ln++;
  477.                 indent = 0;
  478.                 singlequoterr = 0;
  479.             } else {
  480.                 ungetc(c, infile);
  481.                 return('\n');
  482.                 /*NOTREACHED*/
  483.                 break;
  484.             }
  485.             c = fgetc(infile);
  486.         }
  487.     }
  488.  
  489.     if (c == SPACE  ||  c == '\t') {
  490.         do
  491.             c = fgetc(infile);
  492.         while (c == SPACE  ||  c == '\t');
  493.         if (c != '\n') {
  494.             ungetc(c, infile);
  495.             return(SPACE);
  496.         } else
  497.             goto lf;
  498.     }
  499.     return(c);
  500. }
  501.  
  502. /*
  503.  * administer count of error msgs. and suppress if too many
  504.  * administer the status var.s
  505.  * prepend file name to msg.
  506.  * flag error msg.s (not warnings) with '*'
  507.  */
  508. int pr(error)
  509. int error;
  510. {
  511.     int i;
  512.  
  513.     if (singlequoterr)
  514.         return(0);
  515.  
  516.     if (verbose) {
  517.         for (i = stackc; i > 0; i--) {
  518.             printf("%d: type ", i);
  519.             prtype(stack[i].type);
  520.             printf(", indent %d, line %d.\n", stack[i].b_indent, stack[i].b_ln);
  521.         }
  522.     }
  523.  
  524.     if (error == 2) {
  525.         errnmb = 0;
  526.         errstatus = 1;
  527.     } else if (error) {
  528.         errstatus = 1;
  529.         if (errnmb < 0)
  530.             return(0);
  531.         else if (errnmb >= 9) {
  532.             errnmb = -1;
  533.             printf("Other error messages being suppressed.\n");
  534.             return(0);
  535.         }
  536.     } else {
  537.         wstatus = 1;
  538.         if (wnmb < 0)
  539.             return(0);
  540.         else if (errnmb + wnmb >= 9) {
  541.             wnmb = -1;
  542.             puts("Further warning messages being suppressed.\n");
  543.             return(0);
  544.         }
  545.     }
  546.  
  547.     if (filename != NULL) {
  548.         fputs(filename, stdout);
  549.         fputs(": ", stdout);
  550.     }
  551.     if (error)
  552.         putchar('*');
  553.     if (error)
  554.         errnmb++;
  555.     else
  556.         wnmb++;
  557.     return(1);
  558. }
  559.  
  560. void newbrak(newtype)
  561. int newtype;
  562. {
  563.     if (newtype == 0) {
  564.         top = stack;
  565.         stackc = 0;
  566.     } else {
  567.         top++;
  568.         stackc++;
  569.     }
  570.     if (stackc >= STACKSIZ) {
  571.         if (pr(2))
  572.             printf("***stack overflow, line %d.\n", ln);
  573.         exit(3);
  574.     }
  575.  
  576.     top->type = newtype;
  577.     top->b_indent = indent;
  578.     top->b_ln = ln;
  579.  
  580. }
  581.  
  582. void prtype(typ)
  583. int typ;
  584. {
  585.     switch (typ) {
  586.     case BRACE:
  587.         putchar('}');
  588.         break;
  589.     case PAREN:
  590.         putchar(')');
  591.         break;
  592.     case SQBRAK:
  593.         putchar(']');
  594.         break;
  595.     case IF:
  596.         fputs("if", stdout);
  597.         break;
  598.     case IFCOND:
  599.         fputs("if-condition", stdout);
  600.         break;
  601.     case THEN:
  602.         fputs("then", stdout);
  603.         break;
  604.     case ELSE:
  605.         fputs("else", stdout);
  606.         break;
  607.     case WHLCOND:
  608.         fputs("while-condition", stdout);
  609.         break;
  610.     default:
  611.         fputs("'NULL'", stdout);
  612.         break;
  613.     }
  614. }
  615.  
  616. void checkcloser(typ)
  617. int (typ);
  618. {
  619.     int i, found;
  620.  
  621.     i = found = 0;
  622.     if (typ == top->type  &&  top->b_indent == indent) {
  623.         rmbrak(1);
  624.         return;
  625.     }
  626.  
  627.     while (!found  &&  ++i < stackc  &&  indent <= (top - i)->b_indent)
  628.         if (typ == (top - i)->type  &&  (top - i)->b_indent == indent)
  629.             found = 1;
  630.  
  631.     if (found) {
  632.         if (pr(1))
  633.             printf("Missing closer%s detected line %d:\n", (i > 1 ? "s" :
  634.               ""), ln);
  635.         while (i--) {
  636.             if (pr(1)) {
  637.                 fputs("\tMissing closing ", stdout);
  638.                 prtype(top->type);
  639.                 printf(" opened line %d.\n", top->b_ln);
  640.             }
  641.             switch (top->type) {
  642.             case BRACE:
  643.                 bracecnt++;
  644.                 break;
  645.             case SQBRAK:
  646.                 sqbrakcnt++;
  647.                 break;
  648.             case PAREN:
  649.                 parencnt++;
  650.                 break;
  651.             default:
  652.                 break;
  653.             }
  654.             rmbrak(1);
  655.         }
  656.         rmbrak(1); /* the matching brak */
  657.     } else if (typ == top->type) {
  658.         if (indent != top->b_indent) {
  659.             if (pr(0)) {
  660.                 fputs("Mismatched indent on closing ", stdout);
  661.                 prtype(typ);
  662.                 printf
  663.                   (" lines %d, %d; indents %d, %d.\n",
  664.                   top->b_ln, ln, top->b_indent, indent);
  665.             }
  666.         }
  667.         rmbrak(1);
  668.     }
  669.       else {
  670.         switch (typ) {
  671.         case BRACE:
  672.             bracecnt--;
  673.             break;
  674.         case SQBRAK:
  675.             sqbrakcnt--;
  676.             break;
  677.         case PAREN:
  678.             parencnt--;
  679.             break;
  680.         default:
  681.             break;
  682.         }
  683.  
  684.         if (pr(1)) {
  685.             fputs("Muddle detected at unmatched closing ", stdout);
  686.             prtype(typ);
  687.             printf(" line %d.\n", ln);
  688.         }
  689.     }
  690. }
  691.  
  692. /*
  693.  * removes IF from stack
  694.  * checks else's indent
  695.  */
  696. void checkelse()
  697. {
  698.     int c;
  699.  
  700.     while ((c = mygetchar()) == SPACE  || c == '\n')
  701.         ;
  702.     if (c == 'e'
  703.       &&  (c = mygetchar()) == 'l'
  704.       &&  (c = mygetchar()) == 's'
  705.       &&  (c = mygetchar()) == 'e'
  706.       &&  !isalpha(c = fgetc(infile))  &&  !isdigit(c)) {
  707.         ungetc(c, infile);
  708.         if (top->type == THEN)
  709.             rmbrak(1);
  710.         if (top->type != IF) {
  711.             if (pr(1))
  712.                 printf("Else with no if line %d.\n", ln);
  713.         }
  714.           else if (indent + 2 < top->b_indent) {
  715.             if (pr(1))
  716.                 printf("Dangling else -- bound to wrong if?  \"if\" line %d, \"e
  717.                    top->b_ln, ln);
  718.         }
  719.           else if (indent != top->b_indent) {
  720.             if (pr(0)) {
  721.                 fputs("Wrong indent for else", stdout);
  722.                 if (indent - 2 >  top->b_indent)
  723.                     fputs(" (missing if?)", stdout);
  724.                 printf(".  \"if\" line %d, \"else\" line %d.\n", top->b_ln,
  725.                    ln);
  726.             }
  727.         }
  728.  
  729.         if (top->type == IF)
  730.             rmbrak(1);
  731.         newbrak(ELSE);
  732.     } else {
  733.         myungetc(c);
  734.         ungetc(SPACE, infile);  /* BUG?? */
  735.         /* no else so terminate the IF */
  736.         if (top->type == IF) {
  737.             rmbrak(1);
  738.             while (top->type == ELSE)
  739.                 rmbrak(1);
  740.             if (top->type == THEN) {
  741.                 rmbrak(1);
  742.                 checkelse();
  743.             }
  744.         }
  745.     }
  746. }
  747.  
  748. /*  This function is included because Aztec C does not include an "abs"
  749.     function.  If your library contains this function, this code can be
  750.     deleted.
  751. */
  752. int abs(i)
  753. {
  754.     int c;
  755.  
  756.     return((i < 0) ? -i : i);
  757. }
  758.